home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-20 / pmpsrc11.zip / CONSOLE.C < prev    next >
Text File  |  1991-07-30  |  19KB  |  873 lines

  1. /*
  2.     console.c -- Screen and keyboard control routines
  3.  
  4.   Poor Man's Packet (PMP)
  5.   Copyright (c) 1991 by Andrew C. Payne    All Rights Reserved.
  6.  
  7.   Permission to use, copy, modify, and distribute this software and its
  8.   documentation without fee for NON-COMMERCIAL AMATEUR RADIO USE ONLY is hereby
  9.   granted, provided that the above copyright notice appear in all copies.
  10.   The author makes no representations about the suitability of this software
  11.   for any purpose.  It is provided "as is" without express or implied warranty.
  12.  
  13.     July, 1989
  14.     Andrew C. Payne
  15.  
  16.     07/30/91 Temporary fix to crashing when scrollback runs out of memory
  17. */
  18.  
  19. /* ----- Includes ----- */
  20. #include <stdio.h>
  21. #include <stdarg.h>
  22. #include <string.h>
  23. #include <conio.h>
  24. #include <dos.h>
  25. #include <bios.h>
  26. #include <alloc.h>
  27. #include <mem.h>
  28. #include "pmp.h"
  29. #include "keys.h"
  30.  
  31. #define VIDEO    0x10    /* video BIOS interrupt */
  32.  
  33. /* ----- Local Stuff ----- */
  34.  
  35. static int    orgcursor;        /* original cursor */
  36.  
  37. static int    cx,cy;            /* saved cursor locations */
  38.  
  39. struct dtext {            /* display text structure */
  40.     byte     attr;        /* display attribute */
  41.     int    len;        /* length of text to display */
  42.     struct dtext *next;    /* next item in linked list */
  43.     byte    data[1];    /* data to display */
  44. };
  45.  
  46. static struct dtext *dtext_head;    /* head of dtext queue */
  47. static struct dtext *dtext_tail;    /* tail of dtext queue */
  48.  
  49. static int dtext_mode;            /* display text mode */
  50.  
  51. #define DTEXT_WRITE    1        /* write to screen */
  52. #define DTEXT_QUEUE    2        /* queue up writes */
  53.  
  54. static byte    *screen_save;        /* saved screen */
  55. static int    savex, savey;        /* saved cursor location */
  56.  
  57. static byte    saveline[160];        /* saved message line */
  58.  
  59. struct vscrline {            /* virtual screen line */
  60.     struct vscrline    *next;        /* next in link */
  61.     struct vscrline    *prev;        /* previous in link */
  62.     int    len;            /* length in bytes */
  63.     char    data[0];        /* line data */
  64. };
  65.  
  66. static struct vscrline    *vscrfirst, *vscrlast;    /* linked list */
  67. static struct vscrline    *vscrstart, *vscrend;    /* start and end of current screen */
  68. static struct vscrline    *vscrorg;        /* original screen */
  69.  
  70. /* ----- Low Level Screen Control ----- */
  71.  
  72. /* v_setctype(start,end)
  73.     Set the cursor size:  start and end.
  74. */
  75. static void cdecl v_setctype(int s,int e)
  76. {
  77.     _AH = 1;
  78.     _CH = s;
  79.     _CL = e;
  80.     geninterrupt(VIDEO);
  81. }
  82.  
  83. /* cursave()
  84.     Returns an integer value representing the current cursor size.
  85. */
  86. int cursave(void)
  87. {
  88.     int    s,e;
  89.  
  90.     _AH = 3;
  91.     _BH = 0;
  92.     geninterrupt(VIDEO);
  93.     s = _CH;
  94.     e = _CL;
  95.  
  96.     return (s << 4) | e;
  97. }
  98.  
  99. /* currest(i)
  100.     Given the number returned by 'cursave' above, restores the cursor
  101.     size.
  102. */
  103. void currest(int i)
  104. {
  105.     v_setctype(i >> 4, i & 0xF);
  106. }
  107.  
  108. /* curoff()
  109.     Turns the cursor off.
  110. */
  111. void cdecl curoff(void)
  112. {
  113.     v_setctype(0x0f,0x0f);
  114. }
  115.  
  116. /* curon()
  117.     Turns the cursor on.
  118. */
  119. void cdecl curon(void)
  120. {
  121.     if(monochrome)
  122.         v_setctype(12,13);
  123.     else
  124.         v_setctype(6,7);
  125. }
  126.  
  127. /* v_scroll(n,ulrow,ulcol,lrrow,lrcol,attr)
  128.     Scrolls current display page.  Blank lines are filled with attr.
  129.     Positive 'n' scrolls up, negative down.
  130. */
  131. static void cdecl v_scroll(int n,int ulrow,int ulcol,int lrrow,int lrcol,int attr)
  132. {
  133.     int    mode,lines;
  134.     static int    bpsave;
  135.  
  136.     mode = (n > 0) ? 6 : 7;        /* use vars so as not to trash regs */
  137.     lines = abs(n);
  138.  
  139.     bpsave = _BP;            /* old BIOS trashes BP */
  140.     _AH = mode;
  141.     _AL = lines;
  142.     _CH = ulrow;
  143.     _CL = ulcol;
  144.     _DH = lrrow;
  145.     _DL = lrcol;
  146.     _BH = attr;
  147.     geninterrupt(VIDEO);
  148.     _BP = bpsave;
  149. }
  150.  
  151. /* putstring(x,y,len,attr,string)
  152.     Given an absolute screen position, a buffered length, and a string,
  153. write string to screen. (FAST!!)
  154. */
  155. void putstring(int x, int y, int len, byte attr, char *s)
  156. {
  157.     byte    buf[80*2];        /* buffer for string */
  158.     byte    *p;
  159.     int    i;
  160.  
  161. /* fill buffer with screen data */
  162.     p = buf;
  163.     for(i=0; i<len; i++) {
  164.         if(*s)
  165.             *p++ = *s++;
  166.         else
  167.             *p++ = ' ';    /* buffer with spaces */
  168.  
  169.         *p++ = attr;        /* character attribute */
  170.     }
  171.  
  172. /* write string to screen */
  173.     puttext(x,y,x+len-1,y,buf);
  174. }
  175.  
  176. /* clear_area(line,start,end)
  177.     Clears part of a line.
  178. */
  179. void clear_area(int line, int start, int end)
  180. {
  181.     putstring(start,line,end-start+1,0,"");
  182. }
  183.  
  184. /* ----- CRT Entry and Exit ----- */
  185. /* CRTInit()
  186.     Initialize the screen.
  187. */
  188. void CRTInit()
  189. {
  190.     struct text_info     r;
  191.  
  192. /* Are we monochrome or CGA? */
  193.     gettextinfo(&r);
  194.     monochrome = (r.currmode == MONO);
  195.  
  196.     orgcursor = cursave();        /* save original cursor */
  197.     curoff();
  198.  
  199. /* set the default screen colors */
  200.     if(monochrome) {
  201.         NormalAttr = CYAN;
  202.         MsgAttr = InvAttr = StatusAttr = 0x70;
  203.         BrightAttr = LIGHTCYAN;
  204.     } else {
  205.         NormalAttr = CYAN;
  206.         MsgAttr = InvAttr = StatusAttr = YELLOW;
  207.         BrightAttr = LIGHTCYAN;
  208.         MsgAttr = InvAttr + 0x80;        /* blink */
  209.     }
  210.  
  211.     cx = cy = 1;
  212.     dtext_head = dtext_tail = NULL;
  213.     dtext_mode = DTEXT_WRITE;
  214.     screen_save = NULL;
  215.  
  216. /* initialize the virtual screen stuff */
  217.     vscrfirst = vscrlast = NULL;
  218. }
  219.  
  220. /* CRTExit()
  221.     Close up the screen.
  222. */
  223. void CRTExit()
  224. {
  225.     normal();
  226.     window(1,1,80,25);
  227.     clrscr();
  228.     currest(orgcursor);            /* restore cursor */
  229. }
  230.  
  231. /* ----- Scrollback stuff ----- */
  232.  
  233. /* TrimScreen()
  234.     Trims lines off the front of the virtual screen buffer until
  235.     coreleft() is greater than 32K.
  236.  
  237.     This not the ideal way to do this.  What is really needed is to have
  238.     the scrollback buffer allocated as one big chunk of memory at
  239.     startup.  (acp)
  240. */
  241. static void TrimScreen(void)
  242. {
  243.     struct vscrline    *p;
  244.  
  245.     while(vscrfirst != NULL && coreleft() < 32000) {
  246.         p = vscrfirst->next;
  247.         free(vscrfirst);
  248.         vscrfirst = p;
  249.     }
  250.     if(vscrfirst != NULL)
  251.         vscrfirst->prev = NULL;
  252. }
  253.  
  254. /* AddLine(n)
  255.     Adds the given line number to the scrollback buffer.
  256.  
  257.     Crude version now, doesn't try to save memory by trimming lines.
  258. */
  259. static void AddLine(int n)
  260. {
  261.     struct vscrline    *p;
  262.     byte    temp[160];        /* temp space */
  263.     byte    *q;
  264.     int    len;
  265.  
  266.     TrimScreen();            /* make sure we're not overflowing */
  267.  
  268. /* get line into temp space, and trim off trailing blanks */
  269.     gettext(1,n,80,n,temp);
  270.     q = temp + 158;
  271.     while(q > temp && q[0] == ' ' && q[1] == NormalAttr)
  272.         q -= 2;            /* trim trailing spaces */
  273.  
  274. /* create line record */
  275.     len = q - temp + 2;
  276.     if((p = malloc(sizeof(struct vscrline) + len)) == NULL)
  277.         OutOfMemory();
  278.     memcpy(p->data,temp,p->len = len);
  279.  
  280. /* add line record to doubly-linked list */
  281.     if(vscrlast != NULL)
  282.         vscrlast->next = p;
  283.     p->prev = vscrlast;
  284.     p->next = NULL;
  285.     vscrlast = p;
  286.     if(vscrfirst == NULL)
  287.         vscrfirst = p;
  288. }
  289.  
  290. /* PutLine(vscrline,n)
  291.     Given a pointer to a virtual line record, puts the contents of
  292.     the record on the line specified.
  293. */
  294. static void PutLine(struct vscrline *p, int n)
  295. {
  296.     puttext(1,n,p->len >> 1,n,p->data);
  297. }
  298.  
  299. /* StartScrollback()
  300.     Starts the scrollback mode.  Adds the contents of the current screen
  301.     to the scrollback buffer so it can be part of any scrolls.
  302.  
  303.     Returns TRUE if in scrollback mode.
  304. */
  305. int StartScrollback(void)
  306. {
  307.     int    i;
  308.  
  309.     if(vscrlast == NULL)
  310.         return FALSE;
  311.  
  312.     vscrorg = vscrstart = vscrlast;
  313.     for(i=1; i<24; i++)        /* add rest of screen to buffer */
  314.         AddLine(i);
  315.  
  316.     vscrend = vscrlast;
  317.     SaveScreen(TRUE, FALSE);
  318.     putstring(11,25,1,StatusAttr,"\031");
  319.     return TRUE;
  320. }
  321.  
  322. /* EndSrollback()
  323.     Ends the scrollback mode.  Restores current screen, and removes
  324.     current screen from buffer.
  325. */
  326. void EndScrollback(void)
  327. {
  328.     struct vscrline    *p,*q;
  329.  
  330. /* remove entries representing current screen from list */
  331.     q = vscrorg->next;
  332.     while(q != NULL) {
  333.         p = q;
  334.         q = q->next;
  335.         free(p);
  336.     }
  337.  
  338.     vscrlast = vscrorg;        /* fix up end of list */
  339.     vscrlast->next = NULL;
  340.     RestoreScreen();
  341.     putstring(11,25,1,StatusAttr," ");
  342. }
  343.  
  344. /* MoveScrollback(n)
  345.     Moves the scrollback the increment specified.  (Negative moves
  346.     backward, positive forward).
  347.  
  348.     Returns TRUE if at the end of the virtual screen.
  349. */
  350. int MoveScrollback(int n)
  351. {
  352.     if(n > 0) {
  353.         while(n-- && vscrend->next != NULL) {
  354.             v_scroll(1,0,0,22,79,NormalAttr);
  355.             PutLine(vscrend->next, 23);
  356.             if(vscrstart != NULL)
  357.                 vscrstart = vscrstart->next;
  358.             else
  359.                 vscrstart = vscrfirst;
  360.             vscrend = vscrend->next;
  361.         }
  362.     } else {
  363.         while(n++ && vscrstart != NULL) {
  364.             v_scroll(-1,0,0,22,79,NormalAttr);
  365.             PutLine(vscrstart, 1);
  366.             vscrstart = vscrstart->prev;
  367.             vscrend = vscrend->prev;
  368.         }
  369.     }
  370.  
  371.     return (vscrend->next == NULL);
  372. }
  373.  
  374. /* WriteScrollback(fname)
  375.     Writes the contents of the scrollback buffer to the file specified.
  376.  
  377.     Error checking (on file writes) could be improved.
  378.  
  379.     Also:  if no info has scrolled off the top of the screen, no info
  380.            is written to the file (this needs to be fixed).
  381. */
  382. void WriteScrollback(char *fname)
  383. {
  384.     FILE    *outfile;
  385.     struct vscrline    *p;
  386.     char    temp[85];        /* output line */
  387.     char    *q,*r;
  388.     int    i;
  389.  
  390.     if(StartScrollback()) {        /* add current screen to buffer */
  391.  
  392.         outfile = fopen(fname, "w");
  393.         if(outfile == NULL) {
  394.             uprintf(InvAttr,"    Error:  can't open '%s'\n",fname);
  395.             return;
  396.         }
  397.  
  398.         p = vscrfirst;            /* write buffer contents */
  399.         while(p != NULL) {
  400.             q = temp;
  401.             r = p->data;
  402.             i = p->len >> 1;    /* extract data */
  403.             while(i--) {
  404.                 *q++ = *r;
  405.                 r += 2;
  406.             }
  407.             *q++ = '\n';
  408.             *q = '\0';
  409.             fputs(temp, outfile);    /* error check this! */
  410.  
  411.             p = p->next;
  412.         }
  413.         fclose(outfile);
  414.         EndScrollback();        /* restore buffer */
  415.     }
  416. }
  417.  
  418. /* ----- Upper/Lower Screen Control ----- */
  419.  
  420. /* CheckScroll()
  421.     Check the 'cy' and scroll the screen if necessary.
  422. */
  423. static void CheckScroll(void)
  424. {
  425.     if(cy > 23) {
  426.         AddLine(1);            /* save first screen line */
  427.         v_scroll(1,0,0,22,79,NormalAttr);
  428.         cy = 23;
  429.     }
  430. }
  431.  
  432. /* GotoLeft()
  433.     If the cursor is not at the left margin, moves it there.
  434.  
  435.     NOTE:  Future project:  this routine should queue up calls
  436.     as well in the dtext queue.
  437. */
  438. void GotoLeft(void)
  439. {
  440.     if(dtext_mode == DTEXT_WRITE) {
  441.         if(cx != 1) {
  442.             cx = 1;
  443.             cy++;            /* advance row */
  444.             Capture("\n", 1);    /* pass along to capture too */
  445.         }
  446.         CheckScroll();
  447.     }
  448. }
  449.  
  450. /* GotoXY(x,y)
  451.     Moves upper screen cursor to specified location.
  452. */
  453. void GotoXY(int x, int y)
  454. {
  455.     cx = x;
  456.     cy = y;
  457. }
  458.  
  459. /* _uputtext(attr,s,l)
  460.     Given an attribute, string and length.  Does a fast screen write to
  461.     the upper screen area.
  462. */
  463. static void _uputtext(byte attr, byte *s, int l)
  464. {
  465.     byte    buf[80*2];        /* buffer for string */
  466.     byte    *p;            /* pointer */
  467.     int    x;
  468.  
  469. /* fill buffer until newline, end of string, or end of screen */
  470.     while(l) {
  471.         p = buf;
  472.         x = cx;
  473.         while(x <= 80 && l && *s != '\n') {
  474.             if(*s == '\t') {    /* handle tabs */
  475.                 do {
  476.                     *p++ = ' ';
  477.                     *p++ = attr;
  478.                     x++;
  479.                 } while(x <= 80 && (x % 8));
  480.             } else {
  481.                 *p++ = *s;
  482.                 *p++ = attr;
  483.                 x++;
  484.             }
  485.             s++;
  486.             l--;
  487.         }
  488.  
  489. /* put buffer to screen */
  490.         puttext(cx,cy,x-1,cy,buf);
  491.  
  492. /* update cursor */
  493.         cx = x;
  494.         if(cx > 80 || *s == '\n') {
  495.             cx = 1;
  496.             cy++;
  497.         }
  498.         CheckScroll();
  499.         if(l && *s == '\n') {
  500.             s++;
  501.             l--;
  502.         }
  503.     }
  504. }
  505.  
  506. /* uputtext(attr,s,l)
  507.     Given an attribute, string and length.  Does a fast screen write to
  508.     the upper screen area.  If the screen is not in the write mode, the
  509.     screen write is queued.
  510.  
  511.     Also passes data to catpure file.
  512. */
  513. void uputtext(byte attr,byte *s, int l)
  514. {
  515.     struct dtext    *q;
  516.  
  517.     Capture(s, l);
  518.  
  519.     if(dtext_mode == DTEXT_WRITE)
  520.         _uputtext(attr,s,l);        /* write text */
  521.     else {
  522.  
  523. /* add entry to display write queue */
  524.         if((q = malloc(sizeof(struct dtext) + l)) == NULL)
  525.             OutOfMemory();
  526.         q->attr = attr;
  527.         q->len = l;
  528.         memcpy(q->data,s,l);
  529.         q->next = NULL;
  530.         if(dtext_tail != NULL)
  531.             dtext_tail->next = q;
  532.         dtext_tail = q;
  533.         if(dtext_head == NULL)
  534.             dtext_head = q;
  535.     }
  536. }
  537.  
  538. /* uputs(attr, s)
  539.     Given a string, does a fast put to the upper screen area with the
  540.     attributes given.
  541. */
  542. void uputs(byte attr, char *s)
  543. {
  544.     int    count;
  545.     int    len;
  546.     char    *p,*q;
  547.  
  548. /* minor hack:  extract beeps */
  549.     p = q = s;
  550.     len = 0;
  551.     count = 0;
  552.     while(*q) {
  553.         if(*p != 7) {
  554.             len++;
  555.             *p++ = *q++;
  556.         } else {
  557.             count++;
  558.             q++;
  559.         }
  560.     }
  561.     if(count)
  562.         StartSound(700, 4*count);    /* make some noise */
  563.     uputtext(attr, (byte *) s, len);
  564. }
  565.  
  566. /* _uputs(attr, s)
  567.     Given a string, does a fast put to the upper screen area with the
  568.     attributes given.
  569.  
  570.     NOTE:  This puts routine calls the _uputtext primive, so screen
  571.     writes are never queued.
  572. */
  573. void _uputs(byte attr, char *s)
  574. {
  575.     _uputtext(attr,(byte *)s, strlen(s));
  576. }
  577.  
  578. /* uprintf(attr, format,s)
  579.     Does a printf to the upper screen area, with given attribute.
  580. */
  581. void uprintf(byte attr, char *format, ...)
  582. {
  583.     char    s[1000];
  584.     va_list    argptr;
  585.  
  586.     va_start(argptr, format);
  587.     vsprintf(s, format, argptr);
  588.     va_end(argptr);
  589.     uputs(attr,s);
  590. }
  591.  
  592. /* SaveScreen(f,border)
  593.     Prepares the upper screen for an overwrite.  Subsequent display writes
  594.     are queued for later processing.  If 'f' is TRUE, then the contents
  595.     of the screen are preserved.  If border is true, then the screen is
  596.     cleared and bordered.
  597. */
  598. void SaveScreen(int f, int border)
  599. {
  600.     int    i;
  601.     byte    buf[80*2];
  602.     byte    *p;
  603.  
  604.     dtext_mode = DTEXT_QUEUE;
  605.     if(f) {
  606.         if((screen_save = malloc(80*23*2)) == NULL)
  607.             OutOfMemory();
  608.         gettext(1,1,80,23,screen_save);
  609.         savex = cx;
  610.         savey = cy;
  611.         if(border) {
  612.             p = buf;
  613.             for(i=0; i<80; i++) {
  614.                 *p++ = '─';
  615.                 *p++ = NormalAttr;
  616.             }
  617.             buf[0] = '┌';
  618.             buf[79*2] = '┐';
  619.             puttext(1,1,80,1,buf);
  620.             buf[0] = '└';
  621.             buf[79*2] = '┘';
  622.             puttext(1,23,80,23,buf);
  623.             p = buf;
  624.             *p++ = '│';
  625.             p++;
  626.             for(i=0; i<78; i++) {
  627.                 *p++ = ' ';
  628.                 p++;
  629.             }
  630.             *p++ = '│';
  631.             for(i=2; i<23; i++)
  632.                 puttext(1,i,80,i,buf);
  633.         }
  634.     }
  635. }
  636.  
  637. /* RestoreScreen()
  638.     Restores the upper screen after an overwrite.  Any queued display
  639.     writes are now processed.
  640. */
  641. void RestoreScreen(void)
  642. {
  643.     struct dtext    *n;
  644.  
  645.     dtext_mode = DTEXT_WRITE;
  646.  
  647. /* restore screen if previously saved */
  648.     if(screen_save != NULL) {
  649.         puttext(1,1,80,23,screen_save);
  650.         free(screen_save);
  651.         cx = savex;
  652.         cy = savey;
  653.     }
  654.  
  655. /* process all entries in the dtext queue */
  656.     while(dtext_head != NULL) {
  657.         _uputtext(dtext_head->attr,dtext_head->data,dtext_head->len);
  658.         n = dtext_head->next;
  659.         free(dtext_head);
  660.         dtext_head = n;
  661.     }
  662.     dtext_tail = NULL;
  663. }
  664.  
  665. /* CenterTitle(line,t)
  666.     Given a title string, centers the title inversed on the line given.
  667. */
  668. void CenterTitle(int line, char *t)
  669. {
  670.     GotoXY(40 - (strlen(t) >> 1),line);
  671.     _uputs(InvAttr,t);
  672. }
  673.  
  674. /* ----- High-Level Screen Control ----- */
  675.  
  676. /* StatusLine()
  677.     Redraws the Status line on the bottom of the screen.
  678. */
  679. void StatusLine()
  680. {
  681.     char    buf[82];
  682.     char    *p;
  683.  
  684. /* get user's callsign */
  685.     p = GetAX25Addr(&MyCall);
  686.     CallLength = strlen(p);
  687.  
  688.     sprintf(buf," PMP %-4s│ %-9s                                                    │      ",
  689.         VERSION,p);
  690.     putstring(1,25,80,StatusAttr,buf);
  691. }
  692.  
  693. /* ShowTXRX(tx,rx)
  694.     Shows the TX/RX state on the status line.
  695. */
  696. void ShowTXRX(int tx, int rx)
  697. {
  698.     static char    *txstr[] = { "  ","TX" };
  699.     static char    *rxstr[] = { "  ","RX" };
  700.  
  701.     putstring(75,25,2,StatusAttr,txstr[tx]);
  702.     putstring(78,25,2,StatusAttr,rxstr[rx]);
  703. }
  704.  
  705. /* ----- Link Status Change ----- */
  706.  
  707. /* NotifyStatus(old,new)
  708.     Notifies the user of the new link status.
  709.  
  710.     Also updates status line to changes in link status.
  711. */
  712. void NotifyStatus(int old, int new)
  713. {
  714.     char    *p,*q;
  715.     char    s[70];
  716.  
  717. /* get pointer to destination path */
  718.     p = GetAX25Path(&AX25_Control.header);
  719.  
  720. /* update status line */
  721.     switch(new) {
  722.         case RECOVERY:
  723.         case CONNECTED:
  724.             sprintf(s,"»» %s",p);
  725.             putstring(13+CallLength,25,40,StatusAttr,s);
  726.             break;
  727.         case DISCONNECTED:
  728.             putstring(13+CallLength,25,40,StatusAttr,"");
  729.             break;
  730.         case SETUP:
  731.             sprintf(s,"?? %s",p);
  732.             putstring(13+CallLength,25,40,StatusAttr,s);
  733.             break;
  734.         case DISCONNECTPEND:
  735.             sprintf(s,"-- %s",p);
  736.             putstring(13+CallLength,25,40,StatusAttr,s);
  737.             break;
  738.     }
  739.  
  740. /* show change in link status */
  741.     *s = '\0';
  742.     if(new == CONNECTED && old != RECOVERY) {
  743.         sprintf(s,"***** CONNECTED to %s     ",p);
  744.         StartSound(300,3);
  745.     } else if(new == DISCONNECTED) {
  746.         switch(AX25_Control.dreason) {
  747.             case DISC_LOCAL:
  748.                 q = "";
  749.                 break;
  750.             case DISC_REMOTE:
  751.                 q = "(remote)";
  752.                 break;
  753.             case DISC_TIMEOUT:
  754.                 q = "(timeout)";
  755.                 break;
  756.             case DISC_BUSY:
  757.                 q = "(remote busy)";
  758.                 break;
  759.         }
  760.         sprintf(s,"***** DISCONNECTED from %s    %s ",p,q);
  761.         StartSound(200,3);
  762.     }
  763.  
  764.     if(*s)             /* show string */
  765.         uprintf(InvAttr,"%s\n",s);
  766. }
  767.  
  768. /* ----- Message Line ------ */
  769.  
  770. /* Pause(t)
  771.     Waits the number of BIOS ticks specified or until a key is pressed.
  772.     Calls PeriodicHook() while waiting.
  773. */
  774. void Pause(int delay)
  775. {
  776.     long    t;
  777.  
  778.     t = BiosTime() + delay;
  779.  
  780.     while(!keypressed() && t >= BiosTime())
  781.         PeriodicHook();
  782.  
  783.     if(keypressed())
  784.         getkey();
  785. }
  786.  
  787. /* Notify(s)
  788.     Flashes a message on the message line.
  789. */
  790. void Notify(char *s)
  791. {
  792.     int    cursor;
  793.  
  794.     cursor = cursave();
  795.     putstring(1,24,80,MsgAttr,s);
  796.     Pause(BIOSSEC*2);        /* wait */
  797.     clear_area(24,1,80);
  798.     currest(cursor);
  799. }
  800.  
  801. /* SaveMessage()
  802.     Saves the contents of the message line.
  803. */
  804. void SaveMessage(void)
  805. {
  806.     gettext(1,24,80,24, saveline);
  807. }
  808.  
  809. /* RestoreMessage()
  810.     Restores the contents of the message line.
  811. */
  812. void RestoreMessage(void)
  813. {
  814.     puttext(1,24,80,24,saveline);
  815. }
  816.  
  817. /* ----- Edit Line Input ----- */
  818.  
  819. /* GetInput(prompt,s,len)
  820.     Reads input from the editline into s, (max length 'len')
  821.     Returns TRUE if return was pressed, or FALSE if ESC abort.
  822. */
  823. int GetInput(char *prompt, char *s, int len)
  824. {
  825.     int    i;
  826.     char    c;
  827.     char    *p;
  828.     KEY    k;
  829.     int    cursor;
  830.  
  831. /* show the prompt on the bottom screen line */
  832.     cursor = cursave();
  833.     curon();        /* make sure the cursor is on */
  834.     clear_area(24,1,80);
  835.     gotoxy(1,24);        /* go to start */
  836.     bright();
  837.     cprintf(prompt);
  838.     p = s;
  839.     i = 0;
  840.  
  841. /* loop, handling keypresses */
  842.     while(TRUE) {
  843.         PeriodicHook();        /* handle everything else */
  844.         while(k = Nextkey()) {
  845.             if(c = asciicode(k)) {
  846.                 switch(c) {
  847.                 case '\r':        /* CR */
  848.                 case 27:        /* ESC */
  849.                     *p = '\0';
  850.                     clear_area(24,1,80);
  851.                     currest(cursor);
  852.                     return c == '\r';
  853.                 case '\b':        /* backspace */
  854.                     if(i > 0) {
  855.                         i--;
  856.                         p--;
  857.                         cprintf("\b \b");
  858.                     }
  859.                     break;
  860.                 default:        /* store character */
  861.                     if(i < len) {
  862.                         *p++ = c;
  863.                         i++;
  864.                         bright();
  865.                         putch(c);
  866.                     }
  867.                     break;
  868.                 }
  869.             }
  870.         }
  871.     }
  872. }
  873.